# http://stackoverflow.com/questions/1515357/simple-example-of-how-to-use-ast-nodevisitor
#~ http://docs.python.org/3/library/ast.html 

#~ http://eli.thegreenplace.net/wp-content/uploads/2009/11/codegen.py
#~ http://dev.pocoo.org/hg/sandbox/file/852a1248c8eb/ast/codegen.py

#~ https://github.com/llvmpy/llvmpy/blob/master/llvm_cbuilder/translator.py

code_example1 = """
x = 5
x = x + 3
"""

code_example2 = """
L = [4, 5, 2]
if L[0] > 4:
    print( L[0] )
L[1] = 10
"""

code_example3b = """
A = [2, 0, 4, 3]
max = 0
for x in A:
    if x > max : 
         max = x
         print( x, max )
"""

code_example3 = """
A = [2, 0, 4, 3]
max = 0
for z in range(4):
    if A[z] > max : 
         max = A[z]
         print( z, max )

"""
#
"""       
-----------------------------------------------

int A = {2, 0, 4, 3};
int max = 0;
for (int z=0; z<N; z++)
{
     if (A[z] > max)
     {
         max = A[z];
         cout <<  z << " " << max << endl;
     }
}
"""

code_example4 = """
    a = "labas"
    M = [ [2, 0, 3],
          [1, 4, 3]        ]
    n = len(M[0])   # @cpp/len(M[0])/3/
    for i  in range(n):
        if M[0][i] > M[1][i] : 
            max = M[0][i]
            print( i, max )
    del M[0]
    M.append( 5 )

    def fun(x, y, a=15):
        return x*y+a

"""


import ast 

#~ t = ast.parse('d[x] += v[y, x]')
import re
def custom_changes(src, type='cpp'):
    lines = src.split('\n')
    for i, line in enumerate(lines):
        if '#' in line:
            code, comment = line.split('#', 1)
            if '@'+type  in comment:
                match = re.search('@'+type+r"/(.*?)/(.*?)/", comment)
                if match:
                    search, replace = match.group(1), match.group(2)
                    # escape search
                    for char in "\\(){}[].*?!^$":
                        search = search.replace(char, '\\'+char)
                    search = eval("r'%s'"%search) # make string raw
                    lines[i] = re.sub(search, replace, line)
                    #~ print( 'SUB', repr(search), repr(replace), lines[i] )
                   
                else:
                    print( "BAD custom changes", '@'+type , i, line )
    return '\n'.join(lines)



########################

def find_extraindentation(src):
    extra_indent = 0
    for line in src.split('\n'):
        if line.strip(' \t'):
            extra_indent = len(line)-len(line.lstrip(' '))
            return extra_indent
    
def dedent(src, indentation):
    dedented_lines = []
    for line in src.split('\n'):
        if line.strip(' \t'):
            prefix = line[:indentation]
            line = line[indentation:]
            if prefix.strip(' \t'):  # sometimes spacing is wrong and strip too much
                line = prefix.strip(' \t') + line
        dedented_lines.append(line)
    src = '\n'.join( dedented_lines )
    return src

def indent(src, indentation):
    indented_lines = []
    for line in src.split('\n'):
        if line.strip(' \t'):
            line = ' '*indentation + line
        indented_lines.append(line)
    src = '\n'.join( indented_lines )
    return src

    
import codegen_cpp

from pygments.lexers import PythonLexer, CppLexer
pylexer = PythonLexer(ensurenl=False)

def collect_py_comments(src):
    comments = {}
    for lineno, line in enumerate(src.split('\n')):
        for ttype, tval in pylexer.get_tokens( line ):
            if str(ttype) == 'Token.Comment':
                comments[lineno+1] = tval

    return comments
    

def convert(src, GIFT=True):
    #~ print("\n\n CONVERTING \n\n", src, "\n-------------------------\n")
    src = custom_changes(src, 'cpp')
    extra_indentation = find_extraindentation(src)
    src = dedent(src, extra_indentation)

    t = ast.parse(src)

    #~ print("\n\n---DUMP")
    #~ print( ast.dump(t, annotate_fields=True, include_attributes=False).replace("body=[", "body=[\n    ") .replace("], ", "],\n ") .replace(")), ", ")),\n ") )
    
    cpp_src = codegen_cpp.to_source( t , comments=collect_py_comments(src) )
    if GIFT:
        #~ for char in '~=#{}': # GIFT format spec characters: http://docs.moodle.org/23/en/GIFT_format#Special_Characters_.7E_.3D_.23_.7B_.7D
        for char in '{}': # GIFT format spec characters: http://docs.moodle.org/23/en/GIFT_format#Special_Characters_.7E_.3D_.23_.7B_.7D
            cpp_src.replace(char, '\\'+char)
    cpp_src = indent(cpp_src, extra_indentation)
    return cpp_src

if __name__=='__main__':
    print(convert(code_example3b))
    
    ##################  src CODE here ##########
    #~ 
    #~ code = custom_changes(code_example3, 'cpp')
    #~ 
    #~ t = ast.parse("x = a - 4 * (b - a) ")          
    t = ast.parse("if not x > 5: print(x>4)")          
    #~ print("\n\n---DUMP")
    #~ print( ast.dump(t, annotate_fields=True, include_attributes=False).replace("body=[", "body=[\n    ") .replace("], ", "],\n ") .replace(")), ", ")),\n ") )

    #~ print("\n"*3, " ----- PY ------- \n\n", )
    #~ import codegen
    #~ print (  codegen.to_source( t ) )
    #~ 
    #~ print("\n"*3, " ----- C++ ------- \n\n", )
    #~ 
    print (   codegen_cpp.to_source( t )   )

    ##############################    
